package com.sms.api.service;

import com.sms.api.bean.ApiResult;
import com.sms.api.util.NewUtils;
import com.sms.api.util.RedisUtil;
import com.sms.api.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

/**
 * 短信发送策略  wy
 * 2020/7/29
 */
@Service
public class SmsPolicyService {
	private static final Logger logger = LoggerFactory.getLogger(SmsPolicyService.class);

	private static final String MOBILE_PROFIX = "SMS_MOBILE_";//短信手机号缓存类型
	private static final String IP_PROFIX = "SMS_IP_";//短信手机号缓存类型
	private static final String SMSTIME = "SMSTIME_";//短信手机号缓存有效时长

	//无法获取真实ip解决参考方法（移动、联通手机获取ip）：https://blog.csdn.net/wangyue23com/article/details/107764209
	@Value("${sms.policy.SMS_IP_BLACK_LIST}")
	private String SMS_IP_BLACK_LIST;//【短信策略】IP黑名单,以";"间隔
	@Value("${sms.policy.SMS_IP_WHITE_LIST}")
	private String SMS_IP_WHITE_LIST;//【短信策略】IP白名单，当前IP不做任何策略限制，以“;”间隔
	@Value("${sms.policy.SMS_TIME_SPACING}")
	private String SMS_TIME_SPACING;//【短信策略】单用户(IP)请求短信时间间隔为“60秒”
	@Value("${sms.policy.SMS_COUNT_PER_IP}")
	private String SMS_COUNT_PER_IP;//【短信策略】限制单IP每天请求次数不能超过10次
	@Value("${sms.policy.SMS_COUNT_PER_MOBILE}")
	private String SMS_COUNT_PER_MOBILE;//【短信策略】每个手机号每天最多只能发10条短信

	@Resource
	RedisUtil redisUtil;

	/**
	 * 短信发送策略
	 * @param request
	 * @return
	 */
	public ApiResult policy(String mobile, HttpServletRequest request) {
		ApiResult rest=new ApiResult("0000","短信策略通过");
		//获取ip
		String ipAddr = NewUtils.getRealIp(request);
		String whiteList = SMS_IP_WHITE_LIST;//ip白名单

		//=======如果是IP白名单，直接通过策略===============//
		if(whiteList.indexOf(ipAddr)>=0){
			logger.info("[短信策略]请求IP:"+ipAddr+"，IP白名单放行");
			return rest;
		}

		//===========如果ip黑名单，则直接返回，不通过策略===============//
		String blackList = SMS_IP_BLACK_LIST;//ip黑名单
		if(blackList.indexOf(ipAddr)>=0){
			logger.info("[短信策略]请求IP:"+ipAddr+"，IP黑名单，做拦截");
			return new ApiResult("0001","未发送，当前ip："+ipAddr+"已被限制发送短信，请联系管理员");
		}

		//================【短信策略】限制单IP每天请求次数不能超过10次================//
		int SMSIpCount = Integer.parseInt(SMS_COUNT_PER_IP);
		String ipCountKey = IP_PROFIX+ipAddr;
		int ipCount = StringUtil.isEmpty(redisUtil.get(ipCountKey))?0: Integer.parseInt(redisUtil.get(ipCountKey));
		if(ipCount>=SMSIpCount){
			logger.info("[短信策略]请求IP:"+ipAddr+"，当前IP，今日发送短信次数过多，已超过"+SMSIpCount+"次");
			return new ApiResult("0002","当前IP今日发送短信次数过多，已超过"+SMSIpCount+"次");
		}

		//================【短信策略】每个手机号每天最多只能发10条短信================//
		int SMSMobileCount = Integer.parseInt(SMS_COUNT_PER_MOBILE);
		String mobileCountKey = MOBILE_PROFIX+mobile;
		int mobileCount = StringUtil.isEmpty(redisUtil.get(mobileCountKey))?0: Integer.parseInt(redisUtil.get(mobileCountKey));
		if(mobileCount>=SMSMobileCount){
			logger.info("[短信策略]请求IP:"+ipAddr+"，当前手机号"+mobile+"，今日发送短信次数过多，已超过"+SMSMobileCount+"次");
			return new ApiResult("0003","当前手机号今日发送短信次数过多，已超过"+SMSMobileCount+"次");
		}

		//================【短信策略】单用户(IP)请求短信时间间隔为“60秒”============//
		String rediskeyIp = SMSTIME+ipAddr;
		Long smsTimeSpacing = Long.parseLong(SMS_TIME_SPACING);//【短信策略】单用户(IP)请求短信时间间隔为“60秒”
		if(!StringUtil.isEmpty(redisUtil.get(rediskeyIp))){
			logger.info("[短信策略]请求IP:"+ipAddr+"，请勿频繁请求，再次获取请间隔"+smsTimeSpacing+"秒");
			return new ApiResult("0004","请勿频繁请求，再次获取请间隔"+smsTimeSpacing+"秒");
		}

		//================【短信策略】限制单IP每天请求次数不能超过10次===当前为修改缓存中的次数=============//
		if(ipCount==0){
			redisUtil.setEx(ipCountKey,++ipCount+"",86400, TimeUnit.SECONDS);//1天
		}else{
			redisUtil.setEx(ipCountKey,++ipCount+"",redisUtil.getExpire(ipCountKey), TimeUnit.SECONDS);
		}

		//================【短信策略】每个手机号每天最多只能发10条短信====当前为修改缓存中的次数============//
		if(mobileCount==0){
			redisUtil.setEx(mobileCountKey,++mobileCount+"",86400, TimeUnit.SECONDS);//1天
		}else{
			redisUtil.setEx(mobileCountKey,++mobileCount+"",redisUtil.getExpire(mobileCountKey), TimeUnit.SECONDS);
		}

		//================【短信策略】单用户(IP)请求短信时间间隔为“60秒”====当前为修改缓存中的秒数========//
		//设置当前ip再次发送短信时间间隔为60秒
		redisUtil.setEx(rediskeyIp,ipAddr,smsTimeSpacing, TimeUnit.SECONDS);

		return rest;
	}

}
